/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2008 Philippe Durand <draekz@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Collections.Generic;

using Anculus.Core;

namespace Galaxium.Protocol.GaduGadu
{
	public abstract class GaduCommand : IGaduCommand
	{
		protected CommandHeader _header;
		
		public CommandHeader Header
		{
			get { return _header; }
			set { _header = value; }
		}
		
		public GaduCommand ()
		{
			
		}
		
		public GaduCommand (int type)
		{
			_header = new CommandHeader (type, 0);
		}
		
		public GaduCommand (int type, int length)
		{
			_header = new CommandHeader (type, length);
		}
		
		protected virtual void Read (BinaryReader reader)
		{
			Log.Warn ("Attempting to read command ["+_header.Type+","+_header.Length+"], but not implemented.");
		}
		
		protected virtual void Write (BinaryWriter writer)
		{
			Log.Warn ("Attempting to write command ["+_header.Type+","+_header.Length+"], but not implemented.");
		}
		
		public void FromStream (MemoryStream stream)
		{
			BinaryReader reader = new BinaryReader (stream);
			
			Read (reader);
		}
		
		public void ToStream (MemoryStream stream)
		{
			BinaryWriter writer = new BinaryWriter (stream);
			
			if (_header != null)
			{
				_header.Length = ToByteArray().Length;
				
				_header.ToStream (stream);
			}
			
			Write (writer);
		}
		
		public byte[] ToByteArray ()
        {
        	MemoryStream stream = new MemoryStream ();
        	BinaryWriter writer = new BinaryWriter (stream);
        	
        	Write (writer);
        	stream.Position = 0;
        	
        	BinaryReader reader = new BinaryReader (stream);
			byte[] bytes = reader.ReadBytes ((int)stream.Length);
            
            return bytes;
        }
		
		protected byte[] ReadString (BinaryReader bin)
		{
			List<byte> array = new List<byte> ();
			
			try
			{
	            byte current = bin.ReadByte ();
	            
	            while (current != 0x00)
	            {
	            	array.Add (current);
	            	
	            	current = bin.ReadByte ();
	            }
	        }
	        catch (EndOfStreamException)
	        {
	        	// If we have reached the end of stream, lets finish gracefully.
	        }
            
            return array.ToArray();
		}
		
		protected void WriteString (BinaryWriter bin, string s)
	    {
			byte[] buf = Encoding.UTF8.GetBytes(s);			bin.Write (buf);
			bin.Write ((byte)0);
		}
		
	    protected void WriteIP (BinaryWriter bin, IPAddress adr)
	    {
	        byte[] buf = adr.GetAddressBytes();
	        byte b;
	        
	        b = buf[0];
	        buf[0] = buf[3];
	        buf[3] = b;
	        
	        b = buf[1];
	        buf[1] = buf[2];
	        buf[2] = b;
	        
	        bin.Write (buf);
	    }
	    
		public static byte[] CreateSHA1Hash (string password)
        {
            byte[] pass = Encoding.UTF8.GetBytes(password);
            return new SHA1Managed().ComputeHash(pass);
        }
        
		public static uint CreateGG32Hash (string password, uint seed)
		{
			uint x, y, z;

            y = seed;

            int p = 0;
            for (x = 0; p < password.Length; p++)
            {
                x = (x & 0xffffff00) | Convert.ToByte(password[p]);
                y ^= x;
                y += x;
                x <<= 8;
                y ^= x;
                x <<= 8;
                y -= x;
                x <<= 8;
                y ^= x;

                z = y & 0x1f;
                y = (uint)((uint)y << (int)z) | (uint)((uint)y >> (int)(32 - z));
            }
            return y;
		}
	}
}
